import { Button } from "@cap/ui-solid";
import { Select as KSelect } from "@kobalte/core/select";
import { createMutation } from "@tanstack/solid-query";
import { Channel } from "@tauri-apps/api/core";
import { createSignal, Show } from "solid-js";
import { createStore, produce, reconcile } from "solid-js/store";
import Tooltip from "~/components/Tooltip";
import { createProgressBar } from "~/routes/editor/utils";
import { authStore } from "~/store";
import { exportVideo } from "~/utils/export";
import { commands, type UploadProgress } from "~/utils/tauri";
import { useEditorContext } from "./context";
import { RESOLUTION_OPTIONS } from "./Header";
import {
	Dialog,
	DialogContent,
	MenuItem,
	MenuItemList,
	PopperContent,
	topLeftAnimateClasses,
} from "./ui";

function ShareButton() {
	const { editorInstance, meta, customDomain, editorState, setEditorState } =
		useEditorContext();
	const projectPath = editorInstance.path;

	const upload = createMutation(() => ({
		mutationFn: async () => {
			setUploadState({ type: "idle" });

			console.log("Starting upload process...");

			// Check authentication first
			const existingAuth = await authStore.get();
			if (!existingAuth) {
				throw new Error("You need to sign in to share recordings");
			}

			const metadata = await commands.getVideoMetadata(projectPath);
			const plan = await commands.checkUpgradedAndUpdate();
			const canShare = {
				allowed: plan || metadata.duration < 300,
				reason: !plan && metadata.duration >= 300 ? "upgrade_required" : null,
			};

			if (!canShare.allowed) {
				if (canShare.reason === "upgrade_required") {
					await commands.showWindow("Upgrade");
					throw new Error(
						"Upgrade required to share recordings longer than 5 minutes",
					);
				}
			}

			const uploadChannel = new Channel<UploadProgress>((progress) => {
				console.log("Upload progress:", progress);
				setUploadState(
					produce((state) => {
						if (state.type !== "uploading") return;

						state.progress = Math.round(progress.progress * 100);
					}),
				);
			});

			setUploadState({ type: "starting" });

			// Setup progress listener before starting upload

			console.log("Starting actual upload...");

			await exportVideo(
				projectPath,
				{
					format: "Mp4",
					fps: 30,
					resolution_base: {
						x: RESOLUTION_OPTIONS._1080p.width,
						y: RESOLUTION_OPTIONS._1080p.height,
					},
					compression: "Web",
				},
				(msg) => {
					setUploadState(
						reconcile({
							type: "rendering",
							renderedFrames: msg.renderedCount,
							totalFrames: msg.totalFrames,
						}),
					);
				},
			);

			setUploadState({ type: "uploading", progress: 0 });

			// Now proceed with upload
			const result = meta().sharing
				? await commands.uploadExportedVideo(
						projectPath,
						"Reupload",
						uploadChannel,
						null,
					)
				: await commands.uploadExportedVideo(
						projectPath,
						{
							Initial: { pre_created_video: null },
						},
						uploadChannel,
						null,
					);

			if (result === "NotAuthenticated") {
				throw new Error("You need to sign in to share recordings");
			} else if (result === "PlanCheckFailed")
				throw new Error("Failed to verify your subscription status");
			else if (result === "UpgradeRequired")
				throw new Error("This feature requires an upgraded plan");

			setUploadState({ type: "link-copied" });

			return result;
		},
		onError: (error) => {
			console.error(error);
			commands.globalMessageDialog(
				error instanceof Error ? error.message : "Failed to upload recording",
			);
		},
		onSettled() {
			setTimeout(() => {
				setUploadState({ type: "idle" });
				upload.reset();
			}, 2000);
		},
	}));

	const [uploadState, setUploadState] = createStore<
		| { type: "idle" }
		| { type: "starting" }
		| { type: "rendering"; renderedFrames: number; totalFrames: number }
		| { type: "uploading"; progress: number }
		| { type: "link-copied" }
	>({ type: "idle" });

	createProgressBar(() => {
		if (uploadState.type === "starting") return 0;
		if (uploadState.type === "rendering")
			return (uploadState.renderedFrames / uploadState.totalFrames) * 100;
		if (uploadState.type === "uploading") return uploadState.progress;
	});

	return (
		<div class="relative">
			<Show when={meta().sharing}>
				{(sharing) => {
					const normalUrl = () => new URL(sharing().link);
					const customUrl = () =>
						customDomain.data?.custom_domain
							? new URL(
									`${customDomain.data?.custom_domain}/s/${meta().sharing?.id}`,
								)
							: null;

					const normalLink = `${normalUrl().host}${normalUrl().pathname}`;
					const customLink = `${customUrl()?.host}${customUrl()?.pathname}`;

					const copyLinks = {
						normal: sharing().link,
						custom: customUrl()?.href,
					};

					const [linkToDisplay, setLinkToDisplay] = createSignal<string | null>(
						customDomain.data?.custom_domain &&
							customDomain.data?.domain_verified
							? customLink
							: normalLink,
					);

					const [copyPressed, setCopyPressed] = createSignal(false);

					const copyLink = () => {
						navigator.clipboard.writeText(linkToDisplay() || sharing().link);
						setCopyPressed(true);
						setTimeout(() => {
							setCopyPressed(false);
						}, 2000);
					};

					return (
						<div class="flex gap-3 items-center">
							<Tooltip
								content={
									upload.isPending ? "Reuploading video" : "Reupload video"
								}
							>
								<Button
									disabled={upload.isPending}
									onClick={() => {
										if (editorState.timeline.selection) {
											setEditorState("timeline", "selection", null);
											return;
										}
										upload.mutate();
									}}
									variant="dark"
									class="flex justify-center items-center size-[41px] !px-0 !py-0 space-x-1"
								>
									{upload.isPending ? (
										<IconLucideLoaderCircle class="animate-spin size-4" />
									) : (
										<IconLucideRotateCcw class="size-4" />
									)}
								</Button>
							</Tooltip>
							<Tooltip content="Open link">
								<div class="rounded-xl px-3 py-2 flex flex-row items-center gap-[0.375rem] bg-gray-3 hover:bg-gray-4 transition-colors duration-100">
									<a
										href={
											linkToDisplay() === customLink
												? copyLinks.custom
												: copyLinks.normal
										}
										target="_blank"
										rel="noreferrer"
										class="w-full truncate max-w-[200px]"
									>
										<span class="text-xs text-gray-12">{linkToDisplay()}</span>
									</a>
									{/** Dropdown */}
									<Show
										when={
											customDomain.data?.custom_domain &&
											customDomain.data?.domain_verified
										}
									>
										<Tooltip content="Select link">
											<KSelect
												value={linkToDisplay()}
												onChange={(value) => value && setLinkToDisplay(value)}
												options={[customLink, normalLink].filter(
													(link) => link !== linkToDisplay(),
												)}
												multiple={false}
												itemComponent={(props) => (
													<MenuItem<typeof KSelect.Item>
														as={KSelect.Item}
														item={props.item}
													>
														<KSelect.ItemLabel class="flex-1 text-xs truncate">
															{props.item.rawValue}
														</KSelect.ItemLabel>
													</MenuItem>
												)}
												placement="bottom-end"
												gutter={4}
											>
												<KSelect.Trigger class="flex justify-center items-center transition-colors duration-200 rounded-lg size-[22px] text-gray-12 bg-gray-6 hover:bg-gray-7 group focus:outline-none focus-visible:outline-none">
													<KSelect.Icon>
														<IconCapChevronDown class="size-4 transition-transform duration-200 group-data-[expanded]:rotate-180" />
													</KSelect.Icon>
												</KSelect.Trigger>
												<KSelect.Portal>
													<PopperContent<typeof KSelect.Content>
														as={KSelect.Content}
														class={topLeftAnimateClasses}
													>
														<MenuItemList<typeof KSelect.Listbox>
															as={KSelect.Listbox}
															class="w-[236px]"
														/>
													</PopperContent>
												</KSelect.Portal>
											</KSelect>
										</Tooltip>
									</Show>
									{/** Copy button */}
									<Tooltip content="Copy link">
										<div
											class="flex justify-center items-center transition-colors duration-200 rounded-lg size-[22px] text-gray-12 bg-gray-6 hover:bg-gray-7"
											onClick={copyLink}
										>
											{!copyPressed() ? (
												<IconCapCopy class="size-3" />
											) : (
												<IconLucideCheck class="size-3 svgpathanimation" />
											)}
										</div>
									</Tooltip>
								</div>
							</Tooltip>
						</div>
					);
				}}
			</Show>
			<Dialog.Root open={!upload.isIdle}>
				<DialogContent
					title={"Reupload Recording"}
					confirm={<></>}
					close={<></>}
					class="text-gray-12 dark:text-gray-12"
				>
					<div class="w-[80%] text-center mx-auto relative z-10 space-y-6 py-4">
						<div class="w-full bg-gray-3 rounded-full h-2.5 mb-2">
							<div
								class="bg-blue-9 h-2.5 rounded-full"
								style={{
									width: `${
										uploadState.type === "uploading"
											? uploadState.progress
											: uploadState.type === "link-copied"
												? 100
												: uploadState.type === "rendering"
													? Math.min(
															(uploadState.renderedFrames /
																uploadState.totalFrames) *
																100,
															100,
														)
													: 0
									}%`,
								}}
							/>
						</div>

						<p class="relative z-10 mt-3 text-xs text-white">
							{uploadState.type === "idle" || uploadState.type === "starting"
								? "Preparing to render..."
								: uploadState.type === "rendering"
									? `Rendering video (${uploadState.renderedFrames}/${uploadState.totalFrames} frames)`
									: uploadState.type === "uploading"
										? `Uploading - ${Math.floor(uploadState.progress)}%`
										: "Link copied to clipboard!"}
						</p>
					</div>
				</DialogContent>
			</Dialog.Root>
		</div>
	);
}

export default ShareButton;
